﻿using DGJv3;
using ExtendNetease_DGJModule.MixMusicApi.M;
using ExtendNetease_DGJModule.NeteaseMusic;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Reflection;
using SongInfo = DGJv3.SongInfo;
namespace ExtendNetease_DGJModule
{
    public class ExtendNeteaseModule : SearchModule
    {
        static ExtendNeteaseModule()
        {
            string assemblyPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), @"弹幕姬\plugins\Assembly");
            if (!Directory.Exists(assemblyPath))
            {
                Directory.CreateDirectory(assemblyPath);
            }
            string filePath = Path.Combine(assemblyPath, "BouncyCastle.Crypto.dll");
            if (!File.Exists(filePath))
            {
                File.WriteAllBytes(filePath, Properties.Resources.BouncyCastle_Crypto);
            }
            filePath = Path.Combine(assemblyPath, "RestSharp.dll");
            if (!File.Exists(filePath))
            {
                File.WriteAllBytes(filePath, Properties.Resources.RestSharp);
            }
            //filePath = Path.Combine(assemblyPath, "Grapevine.dll");
            //if (!File.Exists(filePath))
            //{
            //    File.WriteAllBytes(filePath, Properties.Resources.Grapevine);
            //}
            AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
            //干掉其他线程
            KillOutherPRO();
            //启动http监听线程
            StartWebServer();

        }
        /// <summary>
        /// 启动http监听线程
        /// </summary>
        public static void StartWebServer()
        {
            //启动http监听线程
            CacheFilePath = Path.Combine(BaseEXEpath, @"DGJ_CacheFile");
            if (!Directory.Exists(CacheFilePath))
            {
                Directory.CreateDirectory(CacheFilePath);
            }
            var filePath = Path.Combine(CacheFilePath, "ffmpeg.exe");
           
            if (!File.Exists(filePath))
            {
                File.WriteAllBytes(filePath, Properties.Resources.ffmpeg);
            }
            //清理垃圾
            DirectoryInfo theFolder = new DirectoryInfo(CacheFilePath);
            FileInfo[] thefileInfo = theFolder.GetFiles("*.*", SearchOption.TopDirectoryOnly);
            foreach (var item in thefileInfo)
            {
                if (!item.Name.Contains("ffmpeg"))
                {
                    item.Delete();
                    //System.IO.File.Delete(item);
                }
            }
            CacheFFmpgePath = filePath;
            AppDomain.CurrentDomain.ProcessExit += new EventHandler(WebServer_Application_ApplicationExit);
            var port = new Random().Next(49000, 59000);
            var localstring = "http://localhost:" + port + "/";

            LoclWebBaseUrl = localstring;
            System.Threading.Tasks.Task.Factory.StartNew(() => {
                hTTPServer = new ExtendNetease_DGJModule.HTTPServer(CacheFilePath, "localhost", port);
                hTTPServer.Start();
            });
            return;
        }
        private static ExtendNetease_DGJModule.HTTPServer hTTPServer = null;
        static void WebServer_Application_ApplicationExit(object sender, EventArgs e)
        {
            //do cleanup of your class
            if (hTTPServer != null)
            {
                hTTPServer.Stop();
            }
        }
        private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
        {
            string dllName = args.Name.Split(',')[0];
            if (dllName == "BouncyCastle.Crypto")
            {
                string assemblyPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), @"弹幕姬\plugins\Assembly");
                return Assembly.LoadFrom(Path.Combine(assemblyPath, "BouncyCastle.Crypto.dll"));
            }
            else if (dllName == "RestSharp")
            {
                string assemblyPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), @"弹幕姬\plugins\Assembly");
                return Assembly.LoadFrom(Path.Combine(assemblyPath, "RestSharp.dll"));
            }
            //else if (dllName == "Grapevine")
            //{
            //    string assemblyPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), @"弹幕姬\plugins\Assembly");
            //    return Assembly.LoadFrom(Path.Combine(assemblyPath, "Grapevine.dll"));
            //}
            else
            {
                return null;
            }
        }
        // private static string BaseEXEpath = AppDomain.CurrentDomain.RelativeSearchPath ?? AppDomain.CurrentDomain.BaseDirectory;
        private static string BaseEXEpath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), @"弹幕姬\plugins\RunTime");
        //public static IRestServer restServer =null;
        private static bool WebReady = false;
        private static string CacheFilePath;
        private static string CacheFFmpgePath;
        private static string LoclWebBaseUrl;
        private IDictionary<long, LyricInfo> LyricCache { get; } = new Dictionary<long, LyricInfo>();
        private List<SongInfoMix> DownloadsongInfoMixes = new List<SongInfoMix>();

        private List<DownloadSongInfo> DownloadSongInfoCache { get; } = new List<DownloadSongInfo>();
        private static void KillOutherPRO()
        {
            //获取当前进程id
            Process proceMain = Process.GetCurrentProcess();
            Process[] processes = Process.GetProcesses();
            foreach (Process process in processes)//获取所有同名进程id
            {
                if (process.ProcessName == proceMain.ProcessName)
                {
                    if (process.Id != proceMain.Id)//根据进程id删除所有除本进程外的所有相同进程
                        process.Kill();
                }
            }
        }
        public ExtendNeteaseModule()
        {
            string authorName;
            try { authorName = BiliUtils.GetUserNameByUserId(35744708); }
            catch { authorName = "西井丶"; }
            SetInfo("本地网易云喵块", authorName, "847529602@qq.com", NeteaseMusicApi.Version, "可以添加歌单和登录网易云喵~");
            this.GetType().GetProperty("IsPlaylistSupported", BindingFlags.SetProperty | BindingFlags.Public | BindingFlags.Instance).SetValue(this, true); // Enable Playlist Supporting
        }

        public void SetLogHandler(Action<string> logHandler)
        {
            this.GetType().GetProperty("_log", BindingFlags.SetProperty | BindingFlags.NonPublic | BindingFlags.Instance).SetValue(this, logHandler);
        }

        protected override DownloadStatus Download(SongItem item)
        {
            throw new NotImplementedException();
        }

        protected override string GetDownloadUrl(SongItem songInfo)
        {
            try
            {
                var thisTOPSongInfo = TOPSongInfoList.FirstOrDefault(T => T.Id.ToString() == songInfo.SongId);
                if (thisTOPSongInfo != null)
                {
                    return thisTOPSongInfo.Url;
                }
                var thisdownload = DownloadsongInfoMixes.FirstOrDefault(T => T.aId == songInfo.SongId);
                if (thisdownload!=null)
                {
                    return thisdownload.Url;
                }
                else
                {
                    long songId = long.Parse(songInfo.SongId);
                    DownloadSongInfo ds = MainConfig.Instance.LoginSession.LoginStatus ?
                    _GetDownloadSongInfo(MainConfig.Instance.LoginSession, songId, MainConfig.Instance.Quality) :
                    _GetDownloadSongInfo(songId, MainConfig.Instance.Quality);
                    if (ds != null)
                    {
                        if (ds.Type.ToLower() == "mp3")
                        {
                            return ds.Url;
                        }
                        Log($"由于点歌姬目前只支持播放mp3格式,当前单曲:{string.Join(";", songInfo.Singers)} - {songInfo.SongName} 格式:{ds.Type} 无法播放喵");
                    }
                    else
                    {
                        Log($"获取下载链接失败了喵(服务器未返回下载链接)");
                    }
                }
                
            }
            catch (WebException e)
            {
                Log($"获取下载链接失败了喵:{e.Message}\r\n这是由于网络原因导致获取失败, 如果多次出现, 请检查你的网络连接喵。");
            }
            catch (Exception e)
            {
                Log($"获取下载链接失败了喵:{e.Message}");
            }
            return null; // 返回null, 点歌姬会自动移除掉当前歌曲
        }

        [Obsolete("Use GetLyricById instead", true)]
        protected override string GetLyric(SongItem songInfo)
        {
            throw new NotSupportedException();
        }

        protected override string GetLyricById(string Id)
        {
            LyricInfo lyric = null;
            var thisdownload = DownloadsongInfoMixes.FirstOrDefault(T => T.aId == Id);
            var thisTOPSongInfo = TOPSongInfoList.FirstOrDefault(T => T.Id.ToString() == Id);
            if (thisdownload == null && thisTOPSongInfo == null)
            {
                long id = long.Parse(Id);
                try
                {
                    lyric = _GetLyric(id);
                }
                catch (WebException e)
                {
                    Log($"获取歌词失败了喵:{e.Message}\r\n这是由于网络原因导致获取失败, 如果多次出现, 请检查你的网络连接喵。");
                }
                catch (Exception e)
                {
                    Log($"获取歌词失败了喵:{e.Message}");
                }
                return lyric?.GetLyricText();
            }
            else
            {
                return null;
            }
        }

        protected override List<SongInfo> GetPlaylist(string keyword)
        {
            try
            {
                NeteaseMusic.SongInfo[] songs;
                if (long.TryParse(keyword, out long id))
                {
                    songs = MainConfig.Instance.LoginSession.LoginStatus ?
                        NeteaseMusicApi.GetPlayList(MainConfig.Instance.LoginSession, id) :
                        NeteaseMusicApi.GetPlayList(id);
                }
                else
                {
                    string json = NeteaseMusicApi.Search(keyword, SearchType.SongList, 1);
                    JObject j = JObject.Parse(json);
                    if (j["code"].ToObject<int>() == 200)
                    {
                        id = j["result"]["playlists"].Select(p => p["id"].ToObject<long>()).FirstOrDefault();
                        if (id > 0)
                        {
                            songs = MainConfig.Instance.LoginSession.LoginStatus ?
                                NeteaseMusicApi.GetPlayList(MainConfig.Instance.LoginSession, id) :
                                NeteaseMusicApi.GetPlayList(id);
                        }
                        else
                        {
                            Log("在获取歌单时收到了未知的服务器返回喵:" + json);
                            return null;
                        }
                    }
                    else
                    {
                        Log("在获取歌单时收到了未知的服务器返回喵:" + json);
                        return null;
                    }
                }
                NeteaseMusic.SongInfo[] cantPlaySongs = songs.Where(p => !p.CanPlay).ToArray();
                if (cantPlaySongs.Length > 0)
                {
                    if (songs.Length == cantPlaySongs.Length)
                    {
                        Log("该歌单内所有的单曲,网易云都没有版权,所以歌单添加失败了喵");
                        return null;
                    }
                    Log($"以下列出的单曲,网易云暂时没有版权,所以它们被除外了喵~\n{string.Join("\n", cantPlaySongs.Select(p => $"{string.Join("; ", p.Artists.Select(q => q.Name))} - {p.Name}"))}");
                }
                return songs.Where(p => p.CanPlay).Select(p => new SongInfo(this, p.Id.ToString(), p.Name, p.Artists.Select(q => q.Name).ToArray(), null)).ToList();
            }
            catch (WebException e)
            {
                Log($"获取歌单失败了喵:{e.Message}\r\n这是由于网络原因导致获取失败, 如果多次出现, 请检查你的网络连接喵。");
            }
            catch (Exception e)
            {
                Log($"获取歌单失败了喵:{e.Message}");
            }
            return null;
        }
        private List<TOPSongInfo> TOPSongInfoList = new List<TOPSongInfo>();
        protected override SongInfo Search(string keyword)
        {
            try
            {
                if (string.IsNullOrEmpty(keyword))
                {
                    return null;
                }

                keyword = keyword.Trim();
                var pt = "163";
                if (keyword.StartsWith("qq "))
                {
                    pt = "qq";
                    keyword = keyword.Replace("qq ","");
                }
                if (keyword.StartsWith("migu "))
                {
                    pt = "migu";
                    keyword = keyword.Replace("qq ", "migu ");
                }
                if (string.IsNullOrEmpty(pt)|| pt=="163")
                {
                    var TOPSearch = ExtendNetease_DGJModule.MixMusicApi.API.TOPSearch(keyword);
                    if (TOPSearch != null)
                    {
                        Log($"命中快捷列表");
                        TOPSongInfoList.Add(TOPSearch);
                        return new SongInfo(this, TOPSearch.Id.ToString(), TOPSearch.Name, new string[] { "未知" }, "");//暂时不实现歌词
                    }
                    NeteaseMusic.SongInfo song = null;
                    NeteaseMusic.SongInfo[] songs = MainConfig.Instance.LoginSession.LoginStatus ?
                        NeteaseMusicApi.SearchSongs(MainConfig.Instance.LoginSession, keyword, 5) :
                        NeteaseMusicApi.SearchSongs(keyword, 5);
                    //默认移除10秒以内的歌
                    songs = songs.Where(T => T.Duration.Ticks > 10000000 * 10).ToArray();
                    //判断是否拥有作者查询条件
                    if (keyword.Contains(" "))
                    {
                        //取空格分割 最后一个字符串
                        var zz = keyword.Split(' ').Last();
                        //查找是否包含原作者
                        song = songs.FirstOrDefault(T => T.ArtistNames == zz);
                        if (song == null)
                        {
                            song = songs.FirstOrDefault(T => T.ArtistNames.Contains(zz));
                        }
                    }
                    if (song == null)
                    {
                        foreach (var item in songs)
                        {
                            item.Similarity = ExtendNetease_DGJModule.MixMusicApi.API.Compute(item.Name, keyword);
                        }
                        songs = songs.OrderBy(T => T.Similarity).ToArray();
                        song = songs.FirstOrDefault();
                    }
                    
                    if (song?.CanPlay == true)
                    {
                        LyricInfo lyric = null;
                        try
                        {
                            lyric = _GetLyric(song.Id);
                        }
                        catch (Exception e)
                        {
                            Log($"获取歌词失败了喵:{e.Message}");
                        }
                        return new SongInfo(this, song.Id.ToString(), song.Name, song.Artists.Select(p => p.Name).ToArray(), lyric?.GetLyricText());
                    }
                    if (song != null)
                    {
                        keyword = song.Id.ToString();
                    }
                }
                
                //Log($"{song.ArtistNames} - {song.Name} : 暂无版权喵");
                //没有版权调用第三方
                var json = MixMusicApi.API.Search(keyword.Trim(),pt);
                if (!string.IsNullOrEmpty(json))
                {
                    JObject j = JObject.Parse(json);
                    if (j["result"].ToObject<int>() == 100)
                    {
                        SongInfoMix[] songsMix = j["data"]["list"].Select(K => new SongInfoMix(K)).ToArray();
                        var songMix = songsMix.FirstOrDefault();
                        if (songMix!=null)
                        {
                            //第三方歌先下载转换
                            if (!WebReady)
                            {
                                StartWebServer();
                            }
                            var DWjson = MixMusicApi.API.GetDownLoadUrl(songMix);
                            JObject DWj = JObject.Parse(DWjson);
                            if (DWj["result"].ToObject<int>() == 100)
                            {
                                var fit = DWj["data"][songMix.aId];
                                if (fit != null)
                                {
                                    var url = fit["url"].ToString();
                                    if (!string.IsNullOrEmpty(url))
                                    {
                                        var ts = DateTimeOffset.Now.ToUnixTimeMilliseconds();

                                        var type = url.Split('?')[0].Split('.').Last();
                                        var savepath = Path.Combine(CacheFilePath, ts + "." + type);
                                        var mp3savepath = Path.Combine(CacheFilePath, ts + ".mp3");
                                        MixMusicApi.API.DownLoad(url, savepath);
                                        if (type.Contains("m4a"))
                                        {
                                            var ml = "-y -i \"" + savepath + "\" -ar 44100 -ac 2 -acodec mp3 \"" + mp3savepath + "\"";
                                            var pro = new System.Diagnostics.Process();
                                            pro.StartInfo.Arguments = ml;
                                            pro.StartInfo.FileName = CacheFFmpgePath;//要启动的程序外部名称  
                                            pro.StartInfo.CreateNoWindow = true;//不显示控制台窗口
                                            pro.StartInfo.UseShellExecute = true;//使用操作系统shell启动
                                            pro.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
                                            pro.Start();
                                            //pro.BeginOutputReadLine();
                                            pro.WaitForExit();
                                            songMix.FilePath = mp3savepath;
                                            songMix.Url = LoclWebBaseUrl + ts + ".mp3";
                                        }
                                        else
                                        {
                                            songMix.FilePath = savepath;
                                            songMix.Url = LoclWebBaseUrl + ts + "." + type;
                                        }
                                        DownloadsongInfoMixes.Add(songMix);
                                    }

                                }
                            }
                            return new SongInfo(this, songMix.aId.ToString(), songMix.name, songMix.artists, "");//暂时不实现歌词
                        }
                        
                    }
                }
            }
            catch (WebException e)
            {
                Log($"搜索单曲失败了喵:{e.Message}\r\n这是由于网络原因导致搜索失败, 如果多次出现, 请检查你的网络连接喵。");
            }
            catch (Exception e)
            {
                Log($"搜索单曲失败了喵:{e.Message}");
            }
            return null;
        }

        private LyricInfo _GetLyric(long id, bool useCache = true)
        {
            if (!useCache || !LyricCache.ContainsKey(id))
            {
                LyricInfo lyric = NeteaseMusicApi.GetLyric(id);
                LyricCache[id] = lyric;
            }
            return LyricCache[id];
        }

        private DownloadSongInfo _GetDownloadSongInfo(long id, Quality quality, bool useCache = true)
            => _GetDownloadSongInfo(null, id, quality, useCache);

        private DownloadSongInfo _GetDownloadSongInfo(NeteaseSession session, long id, Quality quality, bool useCache = true)
        {
            DownloadSongInfo dsi;
            lock (DownloadSongInfoCache)
            {
                DownloadSongInfoCache.RemoveAll(p => p.ExpireTime < DateTime.Now);
                dsi = DownloadSongInfoCache.Find(p => p.Id == id && p.RequestQuality == quality);
            }
            if (!useCache || dsi == null)
            {
                IDictionary<long, DownloadSongInfo> dss = NeteaseMusicApi.GetSongsUrl(session, MainConfig.Instance.Quality, songIds: id);
                if (dss.TryGetValue(id, out dsi))
                {
                    DownloadSongInfoCache.Add(dsi);
                }
            }
            return dsi;
        }
    }
}
